﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.Diagnostics;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Xml;
using System.Net.NetworkInformation;
using UrlHistoryLibrary;
using System.Collections;

namespace NetManager_Client
{
    public partial class frmMain : Form
    {
        private Socket clientSock;
        private Thread clientTh;
        public static event EventHandler UnlockEvt;
        private delegate void DelegateLock();       
        private string svrIP;
        private string svrPort;

        #region htdu87 functions

        private void ConnectToServer()
        {
            
            while (!clientSock.Connected)
            {
                lblStatus.Text = "Connecting to server...";
                try
                {
                    IPEndPoint ipendpoint = new IPEndPoint(IPAddress.Parse(txtSvrIp.Text), Convert.ToInt32(txtSvrPort.Text));
                    clientSock.Connect(ipendpoint);
                    lblStatus.Text = "Connected to server";
                    RecData(clientSock);
                }
                catch(Exception ex)
                {
                    Debug.Write(ex.Message);
                    //lblStatus.Text = "Faild to connect with server";
                }
            }
        }

        private void RecData(Socket sck)
        {
            while (sck.Connected)
            {
                byte[] byteData = ReceiveData(sck);
                string cmd = (string)ByteToObject(byteData);
                switch (cmd)
                {
                    case "GIVE_ME_YOUR_INFORMATION":
                        string[] machineInfo = new string[] { "GIVE_ME_YOUR_INFORMATION", GetComputerName(), GetOwnIP(), GetMACAddress() };
                        SendData(sck, ObjectToByte(machineInfo));
                        break;
                    case "LOCK":
                        DelegateLock dl = new DelegateLock(ShowLockForm);
                        Invoke(dl, null);
                        break;
                    case "UNLOCK":
                        if (UnlockEvt != null)
                            UnlockEvt(null, null);
                        break;
                    case "BROWSER_HISTORY":
                        ArrayList data = GetHistoryIE();
                        DataTable dataSend = new DataTable();
                        dataSend.Columns.Add("title", typeof(string));
                        dataSend.Columns.Add("url", typeof(string));
                        dataSend.Columns.Add("date", typeof(DateTime));
                        foreach (STATURL s in data)
                        {
                            dataSend.Rows.Add(s.Title, s.URL, s.LastVisited);
                        }

                        object[] res = new object[] { "BROWSER_HISTORY", dataSend };
                        SendData(sck, ObjectToByte(res));
                        break;
                    case "SHUTDOWN":
                        Process.Start("shutdown", "/s /t 30");
                        break;
                    default:
                        break;
                }
            }
        }

        private void SendData(Socket sck, byte[] data)
        {
            int totalSent = 0;
            int totalSize = data.Length;
            int dataLeft = totalSize;
            int sent;
            byte[] datasize = new byte[4];
            datasize = BitConverter.GetBytes(totalSize);
            sck.Send(datasize);
            while(totalSent < totalSize)
            {
                sent = sck.Send(data, totalSent, dataLeft, SocketFlags.None);
                totalSent += sent;
                dataLeft -= sent;

                Debug.WriteLine("Send: send " + totalSent + "/" + totalSize);
                Debug.WriteLine("Send: left " + dataLeft + "/" + totalSize);
            }
        }

        private byte[] ReceiveData(Socket sck)
        {
            int totalReceived = 0;
            int totalSize;
            int receive;
            byte[] totalSizeByte = new byte[4];
            sck.Receive(totalSizeByte, 0, 4, SocketFlags.None);
            totalSize = BitConverter.ToInt32(totalSizeByte, 0);
            int dataLeft = totalSize;
            byte[] data = new byte[totalSize];
            while (totalReceived < totalSize)
            {
                receive = sck.Receive(data, totalReceived, dataLeft, SocketFlags.None);
                totalReceived += receive;
                dataLeft -= receive;
                
                Debug.WriteLine("Receive: receive " + totalReceived + "/" + totalSize);
                Debug.WriteLine("Receive: left " + dataLeft + "/" + totalSize);
            }
            
            return data;
        }

        private byte[] ObjectToByte(object obj)
        {
            BinaryFormatter binary = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            binary.Serialize(ms, obj);
            return ms.ToArray();
        }

        private object ByteToObject(byte[] bytedata)
        {
            if (bytedata == null)
                return null;
            object obj = null;
            try
            {
                BinaryFormatter binary = new BinaryFormatter();
                MemoryStream ms = new MemoryStream(bytedata);
                ms.Position = 0;
                obj = binary.Deserialize(ms);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("htdu87: ByteToObject error: " + ex.Message);
            }
            return obj;
        }

        private string GetOwnIP()
        {
            IPHostEntry host;
            string localIP = "";
            host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (IPAddress ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIP = ip.ToString();
                    break;
                }
            }
            return localIP;
        }

        private string GetComputerName()
        {
            return System.Environment.MachineName;
        }

        private string GetMACAddress()
        {
            NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
            String sMacAddress = string.Empty;
            foreach (NetworkInterface adapter in nics)
            {
                if (sMacAddress == String.Empty)// only return MAC Address from first card  
                {
                    IPInterfaceProperties properties = adapter.GetIPProperties();
                    sMacAddress = adapter.GetPhysicalAddress().ToString();
                }
            } return sMacAddress;
        }

        private void ShowLockForm()
        {
            frmLock frm = new frmLock();
            frm.Show();
        }

        private bool LoadConfig(ref string ip, ref string port)
        {
            if (File.Exists(Application.StartupPath + "/AppConfig.htd"))
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(Application.StartupPath + "/AppConfig.htd");
                XmlNodeList nodelist = xmlDoc.SelectNodes("/NetManagerClient");
                foreach (XmlNode node in nodelist)
                {
                    ip = node["ServerIP"].InnerText;
                    port = node["ServerPort"].InnerText;
                }
                return true;
            }
            else
            {
                MessageBox.Show("Config file not found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return false;
        }

        private bool SaveConfig(string ip, string port)
        {
            if (File.Exists(Application.StartupPath + "/AppConfig.htd"))
            {
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(Application.StartupPath + "/AppConfig.htd");
                XmlNodeList nodelist = xmlDoc.SelectNodes("/NetManagerClient");
                foreach (XmlNode node in nodelist)
                {
                    node["ServerIP"].InnerText = ip;
                    node["ServerPort"].InnerText = port;
                }
                xmlDoc.Save(Application.StartupPath + "/AppConfig.htd");
                return true;
            }
            else
            {
                MessageBox.Show("Error", "Config file not found", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            return false;
        }

        #endregion

        public frmMain()
        {
            CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            notifyIcon1.Icon = Properties.Resources._1379754420_25381;
            //notifyIcon1.ShowBalloonTip(1000);
            if (LoadConfig(ref svrIP, ref svrPort))
            {
                clientSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                frmLock frm = new frmLock();
                frm.Show();
                txtSvrIp.Text = svrIP;
                txtSvrPort.Text = svrPort;
                clientTh = new Thread(() => ConnectToServer());
                clientTh.Start();
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (clientSock.Connected)
            {
                clientSock.Disconnect(false);
                clientSock.Close();
            }

            if (clientTh != null && clientTh.IsAlive)
                clientTh.Abort();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (SaveConfig(txtSvrIp.Text, txtSvrPort.Text))
                Application.Restart();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void configConnectToServerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Normal;
        }

        //-------Read IE history-------------------------
        private ArrayList GetHistoryIE()
        {
            //gv=new DataGridView();
            UrlHistoryWrapperClass urlHistory;
            UrlHistoryWrapperClass.STATURLEnumerator enumerator;
            ArrayList list_GV = new ArrayList();
            urlHistory = new UrlHistoryWrapperClass();
            list_GV.TrimToSize();
            enumerator = urlHistory.GetEnumerator();
            enumerator.SetFilter("http://", STATURLFLAGS.STATURLFLAG_ISTOPLEVEL);
            while (enumerator.MoveNext())
            {
                list_GV.Add(enumerator.Current);
            }
            enumerator.Reset();
            if (list_GV.Count != 0)
            {
                list_GV.Sort(SortFileTimeAscendingHelper.SortFileTimeAscending());
            }
            //gv.DataSource = list_GV;
            return list_GV;
        }
    }
}
